<?php

/*
 * 公用函数库
 * @since 1.0 <2015-5-27> SoChishun Added.
 */
/* 页面头部输出 */
error_reporting(0); //抑制所有错误信息
@header("content-Type: text/html; charset=utf-8"); //语言强制
ob_start();
date_default_timezone_set('Asia/Shanghai'); //此句用于消除时间差
set_time_limit(0); // PHP运行超时限制
session_start(); // 开启session
/* /页面头部输出 */

/**
 * 加载配置文件
 * @return false|array 成功返回array,失败返回false
 * @since 1.0 <2015-5-27> SoChishun Added.
 * @since 1.1 2016-6-17 SoChishun 新增define指令
 */
function load_config() {
    $conf_dir = './conf/';
    $config = include $conf_dir . 'config.php'; // 读取全局配置文件
    $cur_mod = $config['MODULE']; // 读取全局配置当前模块名称
    $module_dir = $conf_dir . $cur_mod . '/';
    $filepath = $module_dir . 'config.php';
    if (!file_exists($filepath)) {
        exit('主模块配置文件不存在!');
    }
    $config = include $filepath; // 读取全局配置当前模块配置
    if (!is_array($config)) {
        exit('主模块配置内容无效!');
    }
    define('MODULE_PATH', $module_dir);
    return $config;
}

/**
 * 层级加载配置中的参数值
 * @param type $config
 * @param type $name
 * @param type $defv
 * @return type
 * @since 1.0 2016-4-1 SoChishun Added.
 */
function c($config, $name, $defv = '') {
    if (!$config) {
        return $defv;
    }
    $anames = explode('.', $name);
    $n = count($anames);
    switch ($n) {
        case 1:
            return isset($config[$name]) ? $config[$name] : $defv;
        case 2:
            list($k1, $k2) = $anames;
            return isset($config[$k1]) && isset($config[$k1][$k2]) ? $config[$k1][$k2] : $defv;
        case 3:
            list($k1, $k2, $k3) = $anames;
            return isset($config[$k1]) && isset($config[$k1][$k2]) && isset($config[$k1][$k2][$k3]) ? $config[$k1][$k2][$k3] : $defv;
            break;
    }
    return $defv;
}

// 获取post数据 2016-3-16
function I($name, $defv = '') {
    if (isset($_POST[$name])) {
        return $_POST[$name] ? $_POST[$name] : $defv;
    } else if (isset($_GET[$name])) {
        return $_GET[$name] ? $_GET[$name] : $defv;
    }
    return $defv;
}

/**
 * 记录日志并输出内容
 * @param string $msg 消息
 * @param boolean $echo 是否输出(true)
 * @since 1.0 2016-6-29 SoChishun Added.
 */
function msglog($msg, $echo = true) {
    if ($echo) {
        echo $msg;
        ob_flush();
        flush();
    }
    file_put_contents('./log/log_' . date('Ymd_Hi') . '.log', strip_tags($msg) . PHP_EOL, FILE_APPEND);
}

/**
 * 批处理执行SQL语句
 * 批处理的指令都认为是execute操作
 * @param array $asqls SQL批处理指令
 * @param boolean $has_title
 * @param array $atpl array('success'=>'','error'=>'')
 * @return boolean
 * @since 1.0 2016-6-15 SoChishun Added.
 * @example patchQuery($asql,false,array('error'=>'%s',));
 */
function patchQuery($asqls = array(), $has_title = false, $atpl = array()) {
    if (!is_array($asqls)) {
        return false;
    }
    $echotpl = array(
        'success' => '<tr><td class="table">%s</td><td class="status break-line al-right">%s</td></tr>',
        'error' => '<tr><td colspan="2" class="status break-line al-right">%s</td></tr>',
    );
    if ($atpl) {
        $echotpl = array_merge($echotpl, $atpl);
    }
    // 自动启动事务支持
    mysql_query("BEGIN");
    try {
        foreach ($asqls as $title => $sql) {
            if (!trim($sql)) {
                continue;
            }
            $result = mysql_query($sql);
            if (false === $result) {
                // 发生错误自动回滚事务
                msglog(sprintf($echotpl['error'], '<span class="red">[' . $title . '] ' . mysql_error() . '</span>'));
                mysql_query("ROLLBACK");
                return false;
            } else {
                if ($has_title) {
                    msglog(sprintf($echotpl['success'], $title, '<span class="ok">安装成功!</span>'));
                }
            }
        }
        // 提交事务
        mysql_query("COMMIT");
        mysql_query("END");
        return true;
    } catch (Exception $ex) {
        // 回滚事务
        msglog(sprintf($echotpl['error'], '<span class="red">[' . $title . '] ' . $ex->getMessage() . '</span>'));
        mysql_query("ROLLBACK");
        mysql_query("END");
        return false;
    }
}

/**
 * 加载sql文件为分号分割的数组
 * <br />支持存储过程和函数提取，自动过滤注释
 * <br />不要在行后面写注释，如: ... -- 行内注释内容无法被识别过滤，将导致错误!
 * @param string $path 文件路径
 * @return boolean|array
 * @since 1.0 <2015-5-27> SoChishun Added.
 * @since 1.1 2016-9-6 SoChishun 修正drop function或drop procedure无法解析的问题
 */
function load_sql_file_to_array($path, $fn_splitor = ';;') {
    if (!file_exists($path)) {
        return false;
    }
    $lines = file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    $arr = false;
    $str = '';
    $skip = false;
    $fn = false;
    foreach ($lines as $line) {
        $line = trim($line);
        if (!$line) {
            continue; // 过滤空行
        }
        // 过滤注释
        if (0 === strpos($line, '--') || 0 === strpos('*') || 0 === strpos($line, '/*') || (false !== strpos($line, '*/') && strlen($line) == (strpos($line, '*/') + 2))) {
            if (!$skip && 0 === strpos($line, '/*')) {
                $skip = true;
            }
            if ($skip && false !== strpos($line, '*/') && strlen($line) == (strpos($line, '*/') + 2)) {
                $skip = false;
            }
            continue;
        }
        if ($skip) {
            continue;
        }
        // 提取存储过程和函数
        if (0 === strpos($line, 'DELIMITER ' . $fn_splitor)) {
            $fn = true;
            continue;
        }
        if (0 === strpos($line, 'DELIMITER ;')) {
            $fn = false;
            $arr[] = $str;
            $str = '';
            continue;
        }
        if ($fn) {
            if (0 === strpos(strtolower($line), 'drop function ') || 0 === strpos(strtolower($line), 'drop procedure ')) {
                $arr[] = $line;
                $str = '';
                continue;
            }
            $str.=$line . ' ';
            continue;
        }
        // 提取普通语句
        $str.=$line;
        if (false !== strpos($line, ';') && strlen($line) == (strpos($line, ';') + 1)) {
            $arr[] = $str;
            $str = '';
        }
    }
    return $arr;
}

/**
 * 从目录加载所有函数或存储过程
 * @param string $path
 * @return array
 * @since 1.0 2016-9-6 SoChishun Added.
 */
function load_routine_sqlfiles_from_folder($path = './conf/siluntang/udml.eshop/routine') {
    $asqls = array();
    $asqlstemp = array();
    $dir = opendir($path);
    while (false !== ($file = readdir($dir))) {
        if ('.' == $file || '..' == $file) {
            continue;
        }
        $path2 = $path . '/' . $file;
        // 路径是文件
        if (is_file($path2)) {
            if (!strpos($file, '.sql')) {
                continue;
            }
            $asqlstemp = load_sql_file_to_array($path2);
            if (!$asqlstemp) {
                continue;
            }
            foreach ($asqlstemp as $sql) {
                $asqls[get_routine_name($sql)] = $sql;
            }
            continue;
        }
        // 路径是目录
        $dir2 = opendir($path . '/' . $file);
        while (false != ($file2 = readdir($dir2))) {
            $path3 = $path2 . '/' . $file2;
            if (is_dir($path3)) {
                continue;
            }
            if (!strpos($file2, '.sql')) {
                continue;
            }
            $asqlstemp = load_sql_file_to_array($path3);
            if (!$asqlstemp) {
                continue;
            }
            foreach ($asqlstemp as $sql) {
                $asqls[get_routine_name($sql)] = $sql;
            }
        }
        closedir($dir2);
    }
    closedir($dir);
    return $asqls;
}

/**
 * 获取函数或存储过程语句的名称
 * @param string $str
 * @return string
 * @since 1.0 2016-9-6 SoChishun Added.
 */
function get_routine_name($str) {
    $str = str_replace(' if exists ', ' ', strtolower($str));
    $astr = explode(' ', $str, 4);
    if (count($astr) > 3) {
        unset($astr[3]);
    }
    $str = implode(' ', $astr);
    $str=  str_replace(';', '', $str);
    if ($pos = strpos($str, '(')) {
        $str = substr($str, 0, $pos);
    }
    return $str.'...';
}

/**
 * 从文件夹加载sql文件
 * <br />适用于udml目录
 * @param type $path
 * @return type
 * @since 1.0 2016-8-22 SoChishun Added.
 */
function load_sqlfiles_from_folder($path = './conf/siluntang/udml.eshop') {
    $asqls = array();
    $dir = opendir($path);
    while (false !== ($file = readdir($dir))) {
        if ('.' == $file || '..' == $file) {
            continue;
        }
        $path2 = $path . '/' . $file;
        if (is_file($path2)) {
            if (!strpos($file, '.sql')) {
                continue;
            }
            $str = file_get_contents($path2);
            if (!$str) {
                continue;
            }
            $asqls[substr($file, 0, -4)] = format_sqlscript($str);
            continue;
        }
        $dir2 = opendir($path . '/' . $file);
        while (false != ($file2 = readdir($dir2))) {
            $path3 = $path2 . '/' . $file2;
            if (is_dir($path3)) {
                continue;
            }
            if (!strpos($file2, '.sql')) {
                continue;
            }
            $str = file_get_contents($path3);
            if (!$str) {
                continue;
            }
            $asqls[substr($file2, 0, -4)] = format_sqlscript($str);
        }
        closedir($dir2);
    }
    closedir($dir);
    return $asqls;
}

/**
 * 格式化sql脚本
 * <br />去除表注释、字段注释、多余空格、drop命令
 * @param type $str
 * @return type
 */
function format_sqlscript($str) {
    $str = preg_replace("/ comment '[^']*'/", '', $str); // comment '...'
    $str = preg_replace("/ comment='[^']*'/", '', $str); // comment='...'
    $str = preg_replace("/--[^\n]+/", '', $str); // -- ...
    $str = preg_replace("/\/\*[^\/]+\//", '', $str); // /*...*/
    $str = preg_replace("/drop[^;]+;/", '', $str); // drop table ...;
    $str = preg_replace('/[\s]+/', ' ', trim($str)); // 多个空格合并成一个
    return $str;
}
